iT邦幫忙

1

Vue3 串接 Google OAuth 登入 【2022 最新】

Ryan 2022-10-05 02:43:197838 瀏覽
  • 分享至 

  • xImage
  •  

前言

大家好,我是 Ryan,這篇文章是我參與 iThome 2022 鐵人賽時與大家分享使用 Nuxt 3 串接 Google OAuth 登入的額外分享,因為在使用 Nuxt 3 串接 Google OAuth 其實等同於在 Vue 3 中做實現,所以獨立了一篇 Vue 3 的範例來分享給大家。

為了讓專案更乾淨,本篇範例使用的是 Vue 3 + Vite 的模板,大家也可以參考下列指令做建立。

npm create vite@latest vue3-google-oauth-example -- --template vue

使用 OAuth 2.0 存取 Google API

首先,我們需要有一組 Google OAuth 使用的 Client ID,你可以到 Google Console 新增一個「OAuth 2.0 用戶端 ID」,這裡我就不再贅述網頁應用程式用的申請過程。

這邊提醒,在建立 OAuth Client ID 時,已授權的 JavaScript 來源,記得填寫上您的正式環境或開發環境的 Domain,且建議使用 HTTPS。
https://ithelp.ithome.com.tw/upload/images/20221005/20152617spwcOfXg04.png

完成後,記得保管好用戶端密碼用戶端 ID (Client ID) 是我們稍後會需要的,用戶端編號格式大概如:

168152363730-b37gnijdpa2rdvvbq0qc29cjh4082t3b.apps.googleusercontent.com

接下來,安裝 Vue 的 Google OAuth 插件,這邊使用的是 vue3-google-login,也有不錯的說明文件可以參考。

使用 NPM 安裝 vue3-google-login

npm install -D vue3-google-login

接著我們在元件中可以直接使用 <GoogleLogin> 元件,並添加一個 callback 屬性。

<script setup>
import { ref } from 'vue'
const data = ref()

const callback = (response) => {
  data.value = response
}
</script>

<template>
  <div>
    <GoogleLogin :callback="callback" />
    <p>
      {{ data }}
    </p>
  </div>
</template>

<style scoped>
p {
  margin-top: 12px;
  word-break: break-all;
}
</style>

接著我們使用 npm run dev 來啟動開發伺服器,就能發現使用 Google 帳號登入成功後,所返回的 Credential。
https://i.imgur.com/8NSdQGl.gif

One Tap prompt

你可以在 <GoogleLogin> 元件添加 prompt 屬性並設為 true,這樣就能同時啟用 Google 一鍵登入 (One Tap prompt) 的功能囉!

<GoogleLogin :callback="callback" prompt/>

或者也可以在 onMounted 中呼叫 vue3-google-logingoogleOneTap() 方法,來單獨使用 One Tap prompt。

<script setup>
import { onMounted } from 'vue'
import { googleOneTap } from 'vue3-google-login'

onMounted(() => {
  googleOneTap()
    .then((response) => {
      console.log(response)
    })
    .catch((error) => {
      console.error(error)
    })
})
</script>

https://i.imgur.com/Z6tDWPv.gif

自訂按鈕

如果你想自訂登入按鈕的樣式,可以在 <GoogleLogin> 的預設插槽 (Slot) 做建立。

<template>
  <GoogleLogin :callback="callback">
    <button>使用 Google 進行登入</button>
  </GoogleLogin>
</template>

使用自訂按鈕會讓 OAuth 流程稍微有點不一樣,當你登入成功後預設會回傳 Auth Code

如果設定屬性 popup-type="TOKEN",則回傳 Access Token

<template>
  <GoogleLogin :callback="callback" popup-type="TOKEN">
    <button>使用 Google 進行登入</button>
  </GoogleLogin>
</template>

使用 googleTokenLogin()

在元件中我們也可以自己建立 handleGoogleAccessTokenLogin 點擊事件,呼叫 googleTokenLogin() 方法並傳入設定在 Runtime Config 中的 Google Client ID,這樣點擊登入按鈕就能處理 Google 登入取得 Access Token。

<script setup>
import { ref } from 'vue'
import { googleTokenLogin } from 'vue3-google-login'

const GOOGLE_CLIENT_ID = '這邊放上你的 Google Client ID'

const data = ref()

const handleGoogleAccessTokenLogin = () => {
  googleTokenLogin({
    clientId: GOOGLE_CLIENT_ID
  }).then((response) => {
    data.value = response
  })
}
</script>

建立一個登入按鈕來呼叫 handleGoogleAccessTokenLogin 點擊事件。

<template>
  <div>
    <button
      type="button"
      @click="handleGoogleAccessTokenLogin"
    >
      使用 Google 進行登入
    </button>
</template>

使用 vue3-google-login 提供的 googleTokenLogin() 方法,我們就能取得 Google 使用者的 Access Token 囉!
https://i.imgur.com/01TiBUZ.gif

使用 googleAuthCodeLogin()

我們也可以使用 googleAuthCodeLogin() 來取得 Auth Code。

<script setup>
import { ref } from 'vue'
import { googleAuthCodeLogin } from 'vue3-google-login'

const GOOGLE_CLIENT_ID = '這邊放上你的 Google Client ID'

const data = ref()

const handleGoogleAuthCodeLogin = () => {
  googleAuthCodeLogin({
    clientId: GOOGLE_CLIENT_ID
  }).then((response) => {
    data.value = response
  })
}
</script>

建立一個登入按鈕來呼叫 handleGoogleAuthCodeLogin 點擊事件。

<template>
  <div>
    <button
      type="button"
      @click="handleGoogleAuthCodeLogin"
    >
      使用 Google 進行登入
    </button>
</template>

取得的就會是 Auth Code。
https://i.imgur.com/E4JokY0.gif

伺服器端驗證

當使用者於前端成功登入後,通常會傳至後端進行登入或記錄使用者,再產生使用於網站的 Token、Cookie 或 Session 等,以供後續的網站驗證做使用。

我們可使用 google-auth-library 於後端進行一系列的驗證或取得使用者資訊。

使用 NPM 安裝 google-auth-library

npm install -D google-auth-library

接下來,我們就能依照不同的登入方式取得的 CredentialAccess TokenAuth Code 送至後端做驗證。

驗證 Access Token

import { OAuth2Client } from 'google-auth-library'

export default (async (accessToken) => {
  const oauth2Client = new OAuth2Client()
  oauth2Client.setCredentials({ access_token: accessToken })

  const userInfo = await oauth2Client
    .request({
      url: 'https://www.googleapis.com/oauth2/v3/userinfo'
    })
    .then((response) => response.data)
    .catch(() => null)

  oauth2Client.revokeCredentials()

  return {
    id: userInfo.sub,
    name: userInfo.name,
    avatar: userInfo.picture,
    email: userInfo.email,
    emailVerified: userInfo.email_verified,
  }
})

驗證 Credential

在元件中,我們使用的登入方式如果是Google 預設渲染的按鈕或 One Tap prompt,回傳值就會包含 Credential,我們將就可使用下面修改後的 Server API 進行驗證。

import { OAuth2Client } from 'google-auth-library'

export default (async (credential) => {
  const oauth2Client = new OAuth2Client()

  const ticket = await oauth2Client.verifyIdToken({
    idToken: credential,
  })

  const payload = ticket.getPayload()

  return {
    id: payload.sub,
    name: payload.name,
    avatar: payload.picture,
    email: payload.email,
    emailVerified: payload.email_verified
  }
})

驗證 Auth Code

import { OAuth2Client } from 'google-auth-library'

export default (async (authCode) => {
  const oauth2Client = new OAuth2Client({
    clientId: '你的 Google Client ID',
    clientSecret: '你的 Google Client Secret',
    redirectUri: '你的 Google Redirect Uri'
  })

  let { tokens } = await oauth2Client.getToken(authCode)
  client.setCredentials({ access_token: tokens.access_token })

  const userInfo = await oauth2Client
    .request({
      url: 'https://www.googleapis.com/oauth2/v3/userinfo'
    })
    .then((response) => response.data)
    .catch(() => null)

  oauth2Client.revokeCredentials()

  return {
    id: userInfo.sub,
    name: userInfo.name,
    avatar: userInfo.picture,
    email: userInfo.email,
    emailVerified: userInfo.email_verified,
  }
})

小結

這篇文章記錄了實現了串接 Google OAuth 登入,大家可以在依照使用情境自己挑選登入方式並將 Access Token 等其他資訊發送至後端進行驗證,後續也能將使用者資訊儲存到資料庫中,有了資料庫我們就能依照使用者資訊,來比對資料庫進行註冊、驗證登入及產生後續的 Session 或 Cookie 等。


感謝大家的閱讀,歡迎大家給予建議 :)

此外我正在參與 iThome 鐵人賽,主題是 Nuxt 3 學習筆記
如果對 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。

範例程式碼

參考文件


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
lovecorgi
iT邦新手 5 級 ‧ 2024-02-27 23:31:43

版主你好,想請問後半部驗證的部分都是在後端執行嗎?

Ryan iT邦新手 1 級 ‧ 2024-03-03 01:11:09 檢舉

您好,是的,伺服器端驗證的段落開始,就是在後端執行的程式來做驗證

lovecorgi iT邦新手 5 級 ‧ 2024-03-03 01:19:27 檢舉

非常謝謝!

1
鯨魚
iT邦新手 5 級 ‧ 2024-03-15 09:52:30

您好,我想要請教關於後端驗證的部分
目前是有想要嘗試,直接在vue3環境中做驗證,參考範例程式碼後,發現在 中引入
import { OAuth2Client } from "google-auth-library"; 會報出錯誤。
想詢問說,是我引入的方式有錯誤嗎?

錯誤訊息

看更多先前的回應...收起先前的回應...
Ryan iT邦新手 1 級 ‧ 2024-03-20 23:30:37 檢舉

關於後端驗證的部分,是需要在後端做使用例如範例中的是以 Nuxt 起的 Server API 來做後端的驗證。

您可以先將完整的範例專案下載下來進行本地的測試,觀察專案的結構與釐清前端與後端的 Server API。

google-auth-library 套件是 Node.js Client,所以在瀏覽器上是無法做執行的。

鯨魚 iT邦新手 5 級 ‧ 2024-03-21 10:02:24 檢舉

好的 謝謝你的說明~
想另外請問,驗證部分是只能透過後端做驗證處理嗎?
如果我前端想要做驗證的話,目前是只能透過 Nuxt 起的 Server API或用NODE.JS 來做後端的驗證這樣是嗎?

Ryan iT邦新手 1 級 ‧ 2024-03-22 15:12:52 檢舉

驗證部分,不是只能在後端做,而是在前端實作會不安全。

若是在前端實作,您的驗證、解密流程與金鑰都是暴露在前端,所以若不依賴後端的驗證手段,都是有可能被使用者惡意竄改或偽造。

Nuxt 是一個可以完成全端的框架,剛好有 Server API 的部分可以實作,你也可以將 Nuxt 當作單純的 Vue 專案或網站,後端 API 使用其他語言來實作,例如 Python、Rust 等都是可行的。
所以你的後端驗證,並沒有限制說一定要 Nuxt 或 Node.js。

鯨魚 iT邦新手 5 級 ‧ 2024-03-23 12:33:26 檢舉

好的 謝謝你仔細的說明, 我明白原因了 真的謝謝~~~
對於驗證的安全性也比較理解了。

0
wl03352521
iT邦新手 5 級 ‧ 2024-05-20 14:41:10

你好,我在使用CSP的時候遇上了問題,這個vue3-google-login有辦法幫他加上nonce或是取得他的sha256嗎?

我要留言

立即登入留言